#include <iostream>
#include "Bank.h"
#define ONSCREEN 0
using namespace std;

// Constructor of the class Bank
Bank::Bank () {}

void // Initializer for the class Bank
Bank::initialize (double input[]) {
    netWorth = input[16];
    wage = input[12];
    beta = input[5];
    sigma = input[10];
    theta = input[11];

    numDstrPartners = 0;
    numUstrPartners = 0;
    partnerDstrFirms = new DownstreamFirm *[static_cast <int> (input[0])];
    partnerUstrFirms = new UpstreamFirm *[static_cast <int> (input[1])];
}

void // Update of bank indicators
Bank::calcQuantities () {
    badDebt = 0;
}

void // Calculate profit and update net worth
Bank::calcNetWorth () {
    double intRate, loan;
    double dstrProfit, ustrProfit;

    dstrProfit = 0;
    for (int i = 0; i < numDstrPartners; i++) {
        intRate = partnerDstrFirms[i]->getBankIR ();
        loan = partnerDstrFirms[i]->getLoan ();
        dstrProfit += intRate * loan;
    }
    ustrProfit = 0;
    for (int i = 0; i < numUstrPartners; i++) {
        intRate = partnerUstrFirms[i]->getBankIR ();
        loan = partnerUstrFirms[i]->getLoan ();
        ustrProfit += intRate * loan;
    }

    netWorth += (dstrProfit + ustrProfit - badDebt);
    if (ONSCREEN == 1) cout << "profit: " << (dstrProfit + ustrProfit) << " badDebt: " << badDebt << " netWorth: " << netWorth << "\n";
}

void
Bank::goBankrupt () {
    for (int i = 0; i < numDstrPartners; i++)
        partnerDstrFirms[i]->delBankPartner ();
    for (int i = 0; i < numUstrPartners; i++)
        partnerUstrFirms[i]->delBankPartner ();
    if (partnerDstrFirms != NULL) delete[] partnerDstrFirms;
    if (partnerUstrFirms != NULL) delete[] partnerUstrFirms;
}

// Methods to deal with the pointers
void
Bank::addDstrPartner (DownstreamFirm *p) {
    partnerDstrFirms[numDstrPartners] = p;
    numDstrPartners ++;
}

void
Bank::delDstrPartner (DownstreamFirm *p) {
    int pos = -1;

    for (int i = 0; i < numDstrPartners; i++)
        if (partnerDstrFirms[i] == p) pos = i;

    if (pos != -1) {
        numDstrPartners --;
        for (int i = pos; i < numDstrPartners; i++)
            partnerDstrFirms[i] = partnerDstrFirms[i+1];
    }
}

void
Bank::addUstrPartner (UpstreamFirm *p) {
    partnerUstrFirms[numUstrPartners] = p;
    numUstrPartners ++;
}

void
Bank::delUstrPartner (UpstreamFirm *p) {
    int pos = -1;

    for (int i = 0; i < numUstrPartners; i++)
        if (partnerUstrFirms[i] == p) pos = i;

    if (pos != -1) {
        numUstrPartners --;
        for (int i = pos; i < numUstrPartners; i++)
            partnerUstrFirms[i] = partnerUstrFirms[i+1];
    }
}

// Accessor methods
double
Bank::getNetWorth () {
    return netWorth;
}

double
Bank::getBankIR (double l) {
    return sigma * pow (netWorth, -beta) + theta * pow (l, theta);
}

void
Bank::incrBadDebt (double bd) {
    badDebt += bd;
}

double
Bank::getBadDebt () {
    return badDebt;
}

bool
Bank::checkInsolvency () {
    bool isInsolvent = false;
    if (netWorth <= 0) isInsolvent = true;
    return isInsolvent;
}

int
Bank::getNumPartners () {
    return numDstrPartners + numUstrPartners;
}
